//
//  UITableView+HHPTableViewManager.m
//  HHPTableViewManager
//
//  Created by 韩红坡 on 2017/3/8.
//  Copyright © 2017年 韩红坡. All rights reserved.
//

#import "UITableView+HHPTableViewManager.h"
#import <objc/runtime.h>
#import "HHPTableViewSectionModel.h"
#import "HHPTableViewCellModel.h"
#import "UITableView+FDTemplateLayoutCell.h"

#ifndef DEBUG
#define DEBUG 0
#endif

@interface HHPTableViewSectionModel (CellModels)

@property (nonatomic, strong, readonly) NSMutableArray *cellModels;

@end

@implementation HHPTableViewSectionModel (CellModels)

- (NSMutableArray *)cellModels
{
    NSMutableArray *cellModels = objc_getAssociatedObject(self, @selector(cellModels));
    if (!cellModels) {
        cellModels = [NSMutableArray array];
        objc_setAssociatedObject(self, @selector(cellModels), cellModels, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    }
    return cellModels;
}

@end

@interface HHPTableViewSectionModel (Private)

@property (nonatomic, weak) UITableView *tableView;

@end

@interface HHPTableViewCellModel (Private)

@property (nonatomic, weak) HHPTableViewSectionModel *sectionModel;

@end

@interface UITableView ()

@property (nonatomic, strong) NSMutableArray *hhp_sectionModels;
@property (nonatomic, strong) NSMutableSet *hhp_cellModels;
@property (nonatomic, assign) BOOL hhp_isReload;
@property (nonatomic, strong, readonly) HHPTableViewSectionModel *hhp_defaultSection;
@property (nonatomic, strong) HHPTableViewCellModel *hhp_selectedCellModel;
@property (nonatomic, strong) NSMutableDictionary *hhp_registerCellDict;

@end

@implementation UITableView (HHPTableViewManager)

#pragma mark - public

- (void)hhp_reloadDataWithBlock:(void (^)(void))block
{
    [self.hhp_sectionModels removeAllObjects];
    [self.hhp_cellModels removeAllObjects];
    
    self.hhp_isReload = YES;
    block();
    self.hhp_isReload = NO;
    
    [self reloadData];
}

- (void)hhp_removeAllSections
{
    [self.hhp_sectionModels removeAllObjects];
    [self.hhp_cellModels removeAllObjects];
    [self reloadData];
}

- (BOOL)hhp_sectionInTableView:(HHPTableViewSectionModel *)sectionModel
{
    return [self.hhp_sectionModels containsObject:sectionModel];
}

- (BOOL)hhp_cellInTableView:(HHPTableViewCellModel *)cellModel
{
    return [self.hhp_cellModels containsObject:cellModel];
}

- (NSIndexPath *)hhp_indexPathForCell:(HHPTableViewCellModel *)cellModel
{
    if (!cellModel.sectionModel) {
        return nil;
    }
    NSInteger sectionIndex = [self.hhp_sectionModels indexOfObject:cellModel.sectionModel];
    if (sectionIndex == NSNotFound) {
        return nil;
    }
    NSInteger rowIndex = [cellModel.sectionModel.cellModels indexOfObject:cellModel];
    if (rowIndex == NSNotFound) {
        return nil;
    }
    NSIndexPath *indexPath = [NSIndexPath indexPathForRow:rowIndex inSection:sectionIndex];
    return indexPath;
}

- (void)hhp_addSection:(HHPTableViewSectionModel *)sectionModel
{
    [self hhp_insertSection:sectionModel atIndex:self.hhp_sectionModels.count];
}

- (void)hhp_insertSection:(HHPTableViewSectionModel *)sectionModel afterSection:(HHPTableViewSectionModel *)anotherSectionModel
{
    [self ensureSectionExists:anotherSectionModel];
    
    NSInteger index = [self.hhp_sectionModels indexOfObject:anotherSectionModel];
    [self hhp_insertSection:sectionModel atIndex:index + 1];
}

- (void)hhp_insertSection:(HHPTableViewSectionModel *)sectionModel beforeSection:(HHPTableViewSectionModel *)anotherSectionModel
{
    [self ensureSectionExists:anotherSectionModel];
    
    NSInteger index = [self.hhp_sectionModels indexOfObject:anotherSectionModel];
    [self hhp_insertSection:sectionModel atIndex:index];
}

- (void)hhp_reloadSection:(HHPTableViewSectionModel *)sectionModel
{
    [self ensureSectionExists:sectionModel];
    
    if (!self.hhp_isReload) {
        NSInteger index = [self.hhp_sectionModels indexOfObject:sectionModel];
        [self reloadSections:[NSIndexSet indexSetWithIndex:index]
            withRowAnimation:UITableViewRowAnimationNone];
    }
}

- (void)hhp_deleteSection:(HHPTableViewSectionModel *)sectionModel
{
    [self ensureSectionExists:sectionModel];
    
    NSInteger index = [self.hhp_sectionModels indexOfObject:sectionModel];
    [self.hhp_sectionModels removeObjectAtIndex:index];
    
    for (HHPTableViewCellModel *cellModel in sectionModel.cellModels) {
        [self.hhp_cellModels removeObject:cellModel];
    }
    
    if (!self.hhp_isReload) {
        [self deleteSections:[NSIndexSet indexSetWithIndex:index]
            withRowAnimation:UITableViewRowAnimationNone];
    }
}

- (void)hhp_addCell:(HHPTableViewCellModel *)cellModel
{
    [self hhp_addCell:cellModel inSection:self.hhp_defaultSection];
}

- (void)hhp_addCells:(NSArray<HHPTableViewCellModel *> *)cellModels
{
    [self hhp_addCells:cellModels inSection:self.hhp_defaultSection];
}

- (void)hhp_insertCell:(HHPTableViewCellModel *)cellModel afterCell:(HHPTableViewCellModel *)anotherCellModel
{
    [self hhp_insertCell:cellModel afterCell:anotherCellModel inSection:self.hhp_defaultSection];
}

- (void)hhp_insertCells:(NSArray<HHPTableViewCellModel *> *)cellModels afterCell:(HHPTableViewCellModel *)anotherCellModel
{
    [self hhp_insertCells:cellModels afterCell:anotherCellModel inSection:self.hhp_defaultSection];
}

- (void)hhp_insertCell:(HHPTableViewCellModel *)cellModel beforeCell:(HHPTableViewCellModel *)anotherCellModel
{
    [self hhp_insertCell:cellModel beforeCell:anotherCellModel inSection:self.hhp_defaultSection];
}

- (void)hhp_insertCells:(NSArray<HHPTableViewCellModel *> *)cellModels beforeCell:(HHPTableViewCellModel *)anotherCellModel
{
    [self hhp_insertCells:cellModels beforeCell:anotherCellModel inSection:self.hhp_defaultSection];
}

- (void)hhp_addCell:(HHPTableViewCellModel *)cellModel inSection:(HHPTableViewSectionModel *)sectionModel
{
    [self hhp_addCells:@[cellModel] inSection:sectionModel];
}

- (void)hhp_addCells:(NSArray<HHPTableViewCellModel *> *)cellModels inSection:(HHPTableViewSectionModel *)sectionModel
{
    [self hhp_insertCells:cellModels atIndex:sectionModel.cellModels.count inSection:sectionModel];
}

- (void)hhp_insertCell:(HHPTableViewCellModel *)cellModel afterCell:(HHPTableViewCellModel *)anotherCellModel inSection:(HHPTableViewSectionModel *)sectionModel
{
    [self hhp_insertCells:@[cellModel] afterCell:anotherCellModel inSection:sectionModel];
}

- (void)hhp_insertCells:(NSArray<HHPTableViewCellModel *> *)cellModels afterCell:(HHPTableViewCellModel *)anotherCellModel inSection:(HHPTableViewSectionModel *)sectionModel
{
    [self ensureRowExists:anotherCellModel];
    
    NSInteger index = [sectionModel.cellModels indexOfObject:anotherCellModel];
    [self hhp_insertCells:cellModels atIndex:index + 1 inSection:sectionModel];
}

- (void)hhp_insertCell:(HHPTableViewCellModel *)cellModel beforeCell:(HHPTableViewCellModel *)anotherCellModel inSection:(HHPTableViewSectionModel *)sectionModel
{
    [self hhp_insertCells:@[cellModel] beforeCell:anotherCellModel inSection:sectionModel];
}

- (void)hhp_insertCells:(NSArray<HHPTableViewCellModel *> *)cellModels beforeCell:(HHPTableViewCellModel *)anotherCellModel inSection:(HHPTableViewSectionModel *)sectionModel
{
    [self ensureRowExists:anotherCellModel];
    
    NSInteger index = [sectionModel.cellModels indexOfObject:anotherCellModel];
    [self hhp_insertCells:cellModels atIndex:index inSection:sectionModel];
}

- (void)hhp_reloadCell:(HHPTableViewCellModel *)cellModel
{
    [self hhp_reloadCells:@[cellModel]];
}

- (void)hhp_reloadCells:(NSArray<HHPTableViewCellModel *> *)cellModels
{
    NSMutableArray<NSIndexPath *> *indexPaths = [NSMutableArray array];
    for (HHPTableViewCellModel *cellModel in cellModels) {
        [self ensureRowExists:cellModel];
        
        NSInteger sectionIndex = [self.hhp_sectionModels indexOfObject:cellModel.sectionModel];
        NSInteger rowIndex = [cellModel.sectionModel.cellModels indexOfObject:cellModel];
        NSIndexPath *indexPath = [NSIndexPath indexPathForRow:rowIndex inSection:sectionIndex];
        [indexPaths addObject:indexPath];
    }
    
    if (!self.hhp_isReload) {
        [self reloadRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationNone];
    }
}

- (void)hhp_deleteCell:(HHPTableViewCellModel *)cellModel
{
    [self hhp_deleteCells:@[cellModel]];
}

- (void)hhp_deleteCells:(NSArray<HHPTableViewCellModel *> *)cellModels
{
    NSMutableArray<NSIndexPath *> *indexPaths = [NSMutableArray array];
    for (HHPTableViewCellModel *cellModel in cellModels) {
        [self ensureRowExists:cellModel];
        
        NSInteger sectionIndex = [self.hhp_sectionModels indexOfObject:cellModel.sectionModel];
        NSInteger rowIndex = [cellModel.sectionModel.cellModels indexOfObject:cellModel];
        NSIndexPath *indexPath = [NSIndexPath indexPathForRow:rowIndex inSection:sectionIndex];
        [indexPaths addObject:indexPath];
        
        [self.hhp_cellModels removeObject:cellModel];
    }
    
    for (HHPTableViewCellModel *cellModel in cellModels) {
        [cellModel.sectionModel.cellModels removeObject:cellModel];
    }
    if (!self.hhp_isReload) {
        [self deleteRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationNone];
    }
}

- (void)hhp_selectCell:(HHPTableViewCellModel *)cellModel
{
    [self ensureRowExists:cellModel];
    
    if (cellModel == self.hhp_selectedCellModel) {
        return;
    }
    
    self.hhp_selectedCellModel = cellModel;
    NSInteger sectionIndex = [self.hhp_sectionModels indexOfObject:cellModel.sectionModel];
    NSInteger rowIndex = [cellModel.sectionModel.cellModels indexOfObject:cellModel];
    NSIndexPath *indexPath = [NSIndexPath indexPathForRow:rowIndex inSection:sectionIndex];
    [self selectRowAtIndexPath:indexPath animated:NO scrollPosition:UITableViewScrollPositionNone];
}

- (void)hhp_deselectCell:(HHPTableViewCellModel *)cellModel
{
    [self ensureRowExists:cellModel];
    
    if (self.hhp_selectedCellModel == cellModel) {
        self.hhp_selectedCellModel = nil;
        NSInteger sectionIndex = [self.hhp_sectionModels indexOfObject:cellModel.sectionModel];
        NSInteger rowIndex = [cellModel.sectionModel.cellModels indexOfObject:cellModel];
        NSIndexPath *indexPath = [NSIndexPath indexPathForRow:rowIndex inSection:sectionIndex];
        [self deselectRowAtIndexPath:indexPath animated:NO];
    }
}

#pragma mark - private properties

- (NSMutableArray *)hhp_sectionModels
{
    NSMutableArray *sections = objc_getAssociatedObject(self, @selector(hhp_sectionModels));
    if (!sections) {
        sections = [NSMutableArray array];
        objc_setAssociatedObject(self, @selector(hhp_sectionModels), sections, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    }
    return sections;
}

- (NSMutableSet *)hhp_cellModels
{
    NSMutableSet *rows = objc_getAssociatedObject(self, @selector(hhp_cellModels));
    if (!rows) {
        rows = [NSMutableSet set];
        objc_setAssociatedObject(self, @selector(hhp_cellModels), rows, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    }
    return rows;
}

- (NSMutableDictionary *)hhp_registerCellDict
{
    NSMutableDictionary *dict = objc_getAssociatedObject(self, @selector(hhp_registerCellDict));
    if (!dict) {
        dict = [NSMutableDictionary dictionary];
        objc_setAssociatedObject(self, @selector(hhp_registerCellDict), dict, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    }
    
    return dict;
}

- (void)setHhp_isReload:(BOOL)hhp_isReload
{
    objc_setAssociatedObject(self, @selector(hhp_isReload), @(hhp_isReload), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (BOOL)hhp_isReload
{
    return [objc_getAssociatedObject(self, @selector(hhp_isReload)) boolValue];
}

- (HHPTableViewSectionModel *)hhp_defaultSection
{
    if (self.hhp_sectionModels.count <= 0) {
        HHPTableViewSectionModel *sectionModel = [HHPTableViewSectionModel new];
        [self hhp_addSection:sectionModel];
    }
    return self.hhp_sectionModels.firstObject;
}

- (void)setHhp_selectedCellModel:(HHPTableViewCellModel *)hhp_selectedCellModel
{
    objc_setAssociatedObject(self, @selector(hhp_selectedCellModel), hhp_selectedCellModel, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}

- (HHPTableViewCellModel *)hhp_selectedCellModel
{
    return objc_getAssociatedObject(self, @selector(hhp_selectedCellModel));
}

- (void)setHhp_didSelectCellBlock:(void (^)(HHPTableViewCellModel *row, BOOL selectionIsChanged))hhp_didSelectCellBlock
{
    objc_setAssociatedObject(self, @selector(hhp_didSelectCellBlock), hhp_didSelectCellBlock, OBJC_ASSOCIATION_COPY);
}

- (void (^)(HHPTableViewCellModel *, BOOL))hhp_didSelectCellBlock
{
    return objc_getAssociatedObject(self, @selector(hhp_didSelectCellBlock));
}

#pragma mark - private

- (void)hhp_insertSection:(HHPTableViewSectionModel *)sectionModel atIndex:(NSInteger)index;
{
    [self ensureSectionNotExists:sectionModel];
    
    sectionModel.tableView = self;
    [sectionModel.cellModels removeAllObjects];
    [self.hhp_sectionModels insertObject:sectionModel atIndex:index];
    
    if (!self.hhp_isReload) {
        // tableview可能会自带一个section，这通常发生在viewDidLoad之后。而viewDidLoad之前不会出现那个自带的section。
        if (!(self.hhp_sectionModels.count == 1 && self.numberOfSections == 1)) {
            [self insertSections:[NSIndexSet indexSetWithIndex:index]
                withRowAnimation:UITableViewRowAnimationNone];
        }
    }
}

- (void)hhp_insertCells:(NSArray<HHPTableViewCellModel *> *)cellModels atIndex:(NSInteger)rowIndex inSection:(HHPTableViewSectionModel *)sectionModel
{
    [self ensureSectionExists:sectionModel];
    
    NSMutableArray<NSIndexPath *> *indexPaths = [NSMutableArray array];
    NSInteger sectionIndex = [self.hhp_sectionModels indexOfObject:sectionModel];
    NSInteger currentRowIndex = rowIndex;
    for (HHPTableViewCellModel *row in cellModels) {
        if ([self.hhp_cellModels containsObject:row]) {
            @throw [NSException exceptionWithName:HHPTableViewManagerException reason:@"Table view already contains this row." userInfo:nil];
        }
        
        NSString *cellId = NSStringFromClass([row cellClass]);
        if (![self.hhp_registerCellDict objectForKey:cellId]) {
            [self registerClass:[row cellClass] forCellReuseIdentifier:cellId];
        }
        
        NSIndexPath *indexPath = [NSIndexPath indexPathForRow:currentRowIndex inSection:sectionIndex];
        [indexPaths addObject:indexPath];
        currentRowIndex++;
    }
    
    currentRowIndex = rowIndex;
    for (HHPTableViewCellModel *row in cellModels) {
        row.sectionModel = sectionModel;
        [sectionModel.cellModels insertObject:row atIndex:currentRowIndex];
        currentRowIndex++;
        
        [self.hhp_cellModels addObject:row];
    }
    if (!self.hhp_isReload) {
        [self insertRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationNone];
    }
}

- (void)raiseExceptionWithMessage:(NSString *)message
{
    if (DEBUG) {
        @throw [NSException exceptionWithName:HHPTableViewManagerException
                                       reason:message
                                     userInfo:nil];
    } else {
        NSLog(@"%@", message);
    }
}

- (void)ensureSectionExists:(HHPTableViewSectionModel *)sectionModel
{
    if (![self.hhp_sectionModels containsObject:sectionModel]) {
        [self raiseExceptionWithMessage:@"Target section is not in this tableview."];
    }
}

- (void)ensureSectionNotExists:(HHPTableViewSectionModel *)sectionModel
{
    if ([self.hhp_sectionModels containsObject:sectionModel]) {
        [self raiseExceptionWithMessage:@"Table view already contains this section."];
    }
}

- (void)ensureRowExists:(HHPTableViewCellModel *)cellModel
{
    if (![self.hhp_cellModels containsObject:cellModel]) {
        [self raiseExceptionWithMessage:@"Target row is not in this tableview."];
    }
}

- (void)ensureRowNotExists:(HHPTableViewCellModel *)cellModel
{
    if ([self.hhp_cellModels containsObject:cellModel]) {
        [self raiseExceptionWithMessage:@"Table view already contains this row."];
    }
}

@end

@implementation UITableView (HHPTableViewHelpers)

- (NSInteger)hhp_numberOfSections
{
    return self.hhp_sectionModels.count;
}

- (NSInteger)hhp_numberOfRowsInSection:(NSInteger)sectionIndex
{
    HHPTableViewSectionModel *section = self.hhp_sectionModels[sectionIndex];
    return section.cellModels.count;
}

- (UITableViewCell *)hhp_cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    HHPTableViewSectionModel *section = self.hhp_sectionModels[indexPath.section];
    HHPTableViewCellModel *cellModel = section.cellModels[indexPath.row];
    NSString *cellId = NSStringFromClass([cellModel cellClass]);
    UITableViewCell *cell = [self dequeueReusableCellWithIdentifier:cellId];
    if (!cell) {
        cell = [[[cellModel cellClass] alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellId];
    }
    
    if ([cell respondsToSelector:@selector(setCellModel:)]) {
        [cell performSelector:@selector(setCellModel:) withObject:cellModel];
    }
    
    return cell;
}

- (UITableViewHeaderFooterView *)hhp_viewForHeaderInSection:(NSInteger)sectionIndex
{
    HHPTableViewSectionModel *section = self.hhp_sectionModels[sectionIndex];
    UITableViewHeaderFooterView *view;
    if (section.headerViewModel && [section.headerViewModel headerFooterViewClass]) {
        NSString *headerId = NSStringFromClass([section.headerViewModel headerFooterViewClass]);
        [self registerClass:[section.headerViewModel headerFooterViewClass] forHeaderFooterViewReuseIdentifier:headerId];
        view = [self dequeueReusableHeaderFooterViewWithIdentifier:headerId];
        if (!view) {
            view = [[[section.headerViewModel headerFooterViewClass] alloc] initWithReuseIdentifier:headerId];
        }
        if ([view respondsToSelector:@selector(setViewModel:)]) {
            [view performSelector:@selector(setViewModel:) withObject:section.headerViewModel];
        }
    } else {
        // 防止出现白条
        view = (UITableViewHeaderFooterView *)[UIView new];
    }
    return view;
}

- (UITableViewHeaderFooterView *)hhp_viewForFooterInSection:(NSInteger)sectionIndex
{
    HHPTableViewSectionModel *section = self.hhp_sectionModels[sectionIndex];
    UITableViewHeaderFooterView *view;
    if (section.footerViewModel && [section.footerViewModel headerFooterViewClass]) {
        NSString *footerId = NSStringFromClass([section.footerViewModel headerFooterViewClass]);
        [self registerClass:[section.footerViewModel headerFooterViewClass] forHeaderFooterViewReuseIdentifier:footerId];
        view = [self dequeueReusableHeaderFooterViewWithIdentifier:footerId];
        if (!view) {
            view = [[[section.footerViewModel headerFooterViewClass] alloc] initWithReuseIdentifier:footerId];
        }
        
        if ([view respondsToSelector:@selector(setViewModel:)]) {
            [view performSelector:@selector(setViewModel:) withObject:section.footerViewModel];
        }
    } else {
        // 防止出现白条
        view = (UITableViewHeaderFooterView *)[UIView new];
    }
    return view;
}

- (CGFloat)hhp_heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    HHPTableViewSectionModel *section = self.hhp_sectionModels[indexPath.section];
    HHPTableViewCellModel *cellModel = section.cellModels[indexPath.row];
    NSString *cellId = NSStringFromClass([cellModel cellClass]);
    
    CGFloat height = 0;
    if (cellModel.rowHeight > 0) {
        height = cellModel.rowHeight;
    } else {
        if ([cellModel respondsToSelector:@selector(cellHeight)]) {
            height = [cellModel cellHeight];
        }
        
        if (height <= 0) {
            height = [self fd_heightForCellWithIdentifier:cellId cacheByIndexPath:indexPath configuration:^(id cell) {
                if ([cell respondsToSelector:@selector(setCellModel:)]) {
                    [cell performSelector:@selector(setCellModel:) withObject:cellModel];
                }
            }];
        }
    }
    
    return height;
}

- (CGFloat)hhp_heightForHeaderInSection:(NSInteger)sectionIndex
{
    HHPTableViewSectionModel *section = self.hhp_sectionModels[sectionIndex];
    if (section.headerViewModel && [section.headerViewModel respondsToSelector:@selector(headerFooterViewHeight)]) {
        return [section.headerViewModel headerFooterViewHeight];
    } else {
        if (section.headerHeight > 0) {
            return section.headerHeight;
        }
        return 0.01;
    }
}

- (CGFloat)hhp_heightForFooterInSection:(NSInteger)sectionIndex
{
    HHPTableViewSectionModel *section = self.hhp_sectionModels[sectionIndex];
    if (section.footerViewModel && [section.footerViewModel respondsToSelector:@selector(headerFooterViewHeight)]) {
        return [section.footerViewModel headerFooterViewHeight];
    } else {
        if (section.footerHeight > 0) {
            return section.headerHeight;
        }
        return 0.01;
    }
}

- (void)hhp_willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
    HHPTableViewSectionModel *section = self.hhp_sectionModels[indexPath.section];
    HHPTableViewCellModel *cellModel = section.cellModels[indexPath.row];
    cell.selectionStyle = (cellModel.cellActionEnabled && cellModel.highlightWhenTapCell) ? UITableViewCellSelectionStyleDefault : UITableViewCellSelectionStyleNone;
}

- (void)hhp_didEndDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
    if ([cell respondsToSelector:@selector(didEndDisplay)]) {
        [cell performSelector:@selector(didEndDisplay)];
    }
}

- (void)hhp_didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    HHPTableViewSectionModel *section = self.hhp_sectionModels[indexPath.section];
    HHPTableViewCellModel *cellModel = section.cellModels[indexPath.row];
    BOOL selectionIsChanged = cellModel != self.hhp_selectedCellModel;
    self.hhp_selectedCellModel = cellModel;
    
    if (cellModel.cellActionEnabled) {
        if (cellModel.didSelectCellBlock) {
            cellModel.didSelectCellBlock(cellModel, selectionIsChanged);
        }
        if (self.hhp_didSelectCellBlock) {
            self.hhp_didSelectCellBlock(cellModel, selectionIsChanged);
        }
    }
    
    if (cellModel.autoDeselect) {
        [self deselectRowAtIndexPath:indexPath animated:YES];
    }
}

- (void)hhp_didDeselectRowAtIndexPath:(NSIndexPath *)indexPath
{
}

- (NSArray<UITableViewRowAction *> *)hhp_editActionsForRowAtIndexPath:(NSIndexPath *)indexPath
{
    HHPTableViewSectionModel *section = self.hhp_sectionModels[indexPath.section];
    HHPTableViewCellModel *cellModel = section.cellModels[indexPath.row];
    
    NSMutableArray *array = [NSMutableArray array];
    
    if (cellModel.rowActionModelArrayBlock) {
        NSArray *rowActionModelArray = cellModel.rowActionModelArrayBlock();
        
        [rowActionModelArray enumerateObjectsUsingBlock:^(HHPRowActionModel * _Nonnull model, NSUInteger idx, BOOL * _Nonnull stop) {
            UITableViewRowAction *rowAction = [UITableViewRowAction rowActionWithStyle:model.actionStyle  title:model.actiontitle handler:^(UITableViewRowAction *action, NSIndexPath *indexPath) {
                if (model.actionBlock) {
                    model.actionBlock(self, cellModel);
                }
            }];
            if (model.actionBackgroundColor) {
                rowAction.backgroundColor = model.actionBackgroundColor;
            }
            
            [array addObject:rowAction];
        }];
    }
    
    return array;
}

- (BOOL)hhp_canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
    HHPTableViewSectionModel *section = self.hhp_sectionModels[indexPath.section];
    HHPTableViewCellModel *cellModel = section.cellModels[indexPath.row];
    
    if (cellModel.rowActionModelArrayBlock) {
        return YES;
    }
    
    return NO;
}

@end
